// 
// SoapTrace.Net - A soap message monitoring utility. 
// 
// Copyright (C) 2004-2009 Matthew Ward
// 
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
// 
// Matthew Ward (mrward@users.sourceforge.net)
// 

using SoapTrace.Core;
using SoapTrace.Core.ApplicationFramework;
using SoapTrace.Core.Communication;
using SoapTrace.Core.Diagnostics;
using SoapTrace.Core.Formatters;
using System;
using System.Collections;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.Remoting;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Xml;
using WinPcap;

namespace SoapTrace
{
	/// <summary>
	/// The class that contains the main Soap Trace application logic.
	/// </summary>
	public class SoapTraceApplication : ISingleInstanceApplicationContext, IDisposable
	{
		/// <summary>
		/// Disposed flag.
		/// </summary>
		private bool m_Disposed;
		
		/// <summary>
		/// Main form for this application.
		/// </summary>
		private MainForm m_MainForm;

		/// <summary>
		/// The application's configuration object.
		/// </summary>
		private SoapTraceConfiguration m_SoapTraceConfiguration = 
			new SoapTraceConfiguration( );

		/// <summary>
		/// Message formatter manager.
		/// </summary>
		private MessageFormatterManager m_FormatterManager;
		
		/// <summary>
		/// Monitors debug messages.
		/// </summary>
		private DebugMessageMonitor m_DebugMessageMonitor = 
			new DebugMessageMonitor( );
		
		/// <summary>
		/// Monitors data packets that have been captured.
		/// </summary>
		private PacketViewer m_PacketViewer;
		
		/// <summary>
		/// The message logging manager.
		/// </summary>
		private SoapMessageLoggingManager m_SoapMessageLoggingManager;
		
		/// <summary>
		/// The request and response messages collection.
		/// </summary>
		private SoapRequestAndResponseCollection
			m_SoapRequestAndResponses = new SoapRequestAndResponseCollection( );		

		/// <summary>
		/// A collection of monitor managers.
		/// </summary>
		private MonitorManagerCollection m_MonitorManagers =
			new MonitorManagerCollection( );
			
		/// <summary>
		/// Creates a new instance of the <see cref="SoapTraceApplication"/>
		/// class.
		/// </summary>
		public SoapTraceApplication( )
		{
			// Set up unhandled exception handler.
			AppDomain CurrentDomain = AppDomain.CurrentDomain;
   			CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler( OnUnhandledException );
		
   			// Set up thread exception handler.
   			Application.ThreadException += new ThreadExceptionEventHandler( OnThreadException );		
		}

		/// <summary>
		/// Disposes this class.
		/// </summary>
		public void Dispose( )
		{
			Dispose( true );

			GC.SuppressFinalize( this );
		}
		
		/// <summary>
		/// Starts up the application.
		/// </summary>
		public void Startup( )
		{
			Logger.Log( "Starting up..." );
			
			try
			{
				ReadConfiguration( );

				CreateMessageFormatters( );

				AddMessageFormattersMenuOptions( );

				InitSoapMonitors( );
				
				CreatePacketViewer( );

				CreateSoapMessageLoggingManager( );
				
				StartSoapMonitors( );

				m_MainForm.Caption = m_MainForm.ActiveViewTitle;
				DisplayUndoCloseMenuItems( );
			}
			catch( SocketException Ex )
			{
				Logger.LogError( Ex.ToString( ) );
				m_MainForm.ShowError( Ex.Message );				
			}
			catch( WinPcapException Ex )
			{
				Logger.LogError( Ex.ToString( ) );
				m_MainForm.ShowError( Ex.Message );
			}
			catch( DllNotFoundException Ex )
			{
				Logger.LogError( Ex.ToString( ) );
				m_MainForm.ShowError( Ex.Message );
			}
			
			Logger.Log( "Started." );
		}

		/// <summary>
		/// Shuts down the application.
		/// </summary>
		public void Shutdown( )
		{
			try
			{
				m_MonitorManagers.Shutdown( );
			}
			catch( SocketException Ex )
			{
				Logger.LogError( Ex.ToString( ) );
				m_MainForm.ShowError( Ex.Message );
			}
			finally
			{
				SaveSettings( );
			}
		}

		/// <summary>
		/// Changes the proxy server or packet capture settings.
		/// </summary>
		public void ChangeSettings( )
		{
			// Show the settings form.
			
			MonitorManager Manager = m_MainForm.ActiveView.Manager;
			
			if( ChangeSettings( Manager ) )
			{
				m_MainForm.ActiveViewTitle = GetCaption( Manager.Config );
				m_MainForm.Caption = GetCaption( Manager.Config );
					
				SaveSettings( );
			}
		}

		/// <summary>
		/// Clears all our saved soap requests and responses that are currently
		/// being displayed.
		/// </summary>
		public void Clear( )
		{
			m_MainForm.Clear( );
			m_MainForm.ActiveView.Manager.Clear( );
		}

		/// <summary>
		/// Reformats the soap messages on display after a message formatter 
		/// has been selected or deselected by the user.
		/// </summary>
		/// <param name="formatterName">The name of the message formatter.</param>
		/// <param name="view">Flag indicating whether the formatter has 
		/// been selected or not.</param>
		public void FormatterSelected( string formatterName, bool view )
		{
			if( view )
			{
				m_FormatterManager.SelectCustomFormatter( formatterName );
				
				EnableFormatterMenuItem( formatterName );

				m_MainForm.DisableNonCustomFormatterMenuItems( );
								
				// Redisplay selected item.

				m_MainForm.ActiveView.Manager.RedisplayItemSelected( );
			}
			else
			{
				m_FormatterManager.DeselectAllCustomFormatters( );
			
				m_MainForm.EnableNonCustomFormatterMenuItems( );
								
				// Redisplay selected item.

				m_MainForm.ActiveView.Manager.RedisplayItemSelected( );
			}
			
			SetRequestTextReadOnlyState( );
		}

		/// <summary>
		/// Sets the word wrap settings for the text controls.
		/// </summary>
		/// <param name="wordWrap">Flag indicating whether word wrap is on or off.
		/// </param>
		public void SetWordWrap( bool wordWrap )
		{
			m_MainForm.WordWrap = wordWrap;
			
		}

		/// <summary>
		/// Displays the <see cref="FontDialog"/> so the user can
		/// change the font for the text controls.
		/// </summary>
		public void ChangeTextFont( )
		{
			FontDialog FontDialog = new FontDialog( );

			FontDialog.Font = m_MainForm.TextFont;
			FontDialog.FontMustExist = true;

			DialogResult Result = FontDialog.ShowDialog( );
			
			if( Result == DialogResult.OK )
			{
				m_MainForm.TextFont = FontDialog.Font;
				
				// Re-colour the displayed items.
				
				m_MainForm.ActiveView.Manager.RedisplayItemSelected( );
			}
		}

		/// <summary>
		/// Displays the <see cref="FontDialog"/> so the user can 
		/// change the font of the list view.
		/// </summary>
		public void ChangeListFont( )
		{
			FontDialog FontDialog = new FontDialog( );

			FontDialog.Font = m_MainForm.ListFont;
			FontDialog.FontMustExist = true;

			DialogResult Result = FontDialog.ShowDialog( );
			
			if( Result == DialogResult.OK )
			{
				m_MainForm.ListFont = FontDialog.Font;
			}
		}

		#region ISingleInstanceApplicationContext Members

		/// <summary>
		/// Redisplays the first instance's main form after a second instance
		/// of the app has been started up.
		/// </summary>
		/// <param name="args">The command line arguments.</param>
		/// <returns>The exit code status.</returns>
		public int RunSecondInstance( string[ ] args )
		{
			// Make the application's main form visible.

			m_MainForm.Redisplay( );

			return 0;
		}

		/// <summary>
		/// Runs the first instance of the soap trace app.
		/// </summary>
		/// <param name="args">The command line arguments.</param>
		/// <returns>The exit code status.</returns>
		public int RunFirstInstance( string[ ] args )
		{
			m_MainForm = new MainForm( this );

			Startup( );

			System.Windows.Forms.Application.Run( m_MainForm );

			return 0;
		}

		#endregion

		/// <summary>
		/// Sets the display state for formatted soap messages.
		/// </summary>
		/// <param name="view">A flag that causes the soap message to
		/// be displayed indented or not.</param>
		public void ViewRawSoapMessage( bool view )
		{
			if( view )
			{
				m_MainForm.ViewSoapMessageParameters = false;
				m_MainForm.UncheckAllFormatters( );
				m_MainForm.ViewRawSoapMessage = view;
			}

			m_FormatterManager.ShowRawSoapMessage = view;
		
			SetRequestTextReadOnlyState( );
			
			m_MainForm.ActiveView.Manager.RedisplayItemSelected( );
		}

		/// <summary> 
		/// Sets the whether to show/hide the soap message envelope.
		/// </summary>
		/// <param name="view">A flag that causes the soap message envelope to
		/// be displayed indented or not.</param>
		public void ViewSoapEnvelope( bool view )
		{
			if( view )
			{	
				m_MainForm.UncheckAllFormatters( );
			}

			m_MainForm.ViewSoapEnvelope = view;
			m_FormatterManager.ShowSoapEnvelope = view;

			SetRequestTextReadOnlyState( );
			
			m_MainForm.ActiveView.Manager.RedisplayItemSelected( );
		}
		
		/// <summary>
		/// Sets whether the http headers are displayed in the
		/// main form.
		/// </summary>
		/// <param name="view">Flag that indicates whether http headers
		/// will be seen in the main form.</param>
		public void ViewHttpHeaders( bool view )
		{
			m_MainForm.ViewHttpHeaders = view;

			if( view )
			{
				m_MainForm.UncheckAllFormatters( );
			}
			
			m_FormatterManager.ShowSoapHeaders = view;

			m_MainForm.ActiveView.Manager.RedisplayItemSelected( );
		}

		/// <summary>
		/// Sets whether the soap message parameters are displayed
		/// without any soap message envelope.
		/// </summary>
		/// <param name="view">Flag that indicates the soap message parameters
		/// will be seen in the main form.</param>
		public void ViewSoapMessageParameters( bool view )
		{
			if( view )
			{
				m_MainForm.ViewRawSoapMessage = false;
				m_MainForm.UncheckAllFormatters( );
			}

			m_MainForm.ViewSoapMessageParameters = view;
			m_FormatterManager.ShowSoapMessageParameters = view;
			
			SetRequestTextReadOnlyState( );

			m_MainForm.ActiveView.Manager.RedisplayItemSelected( );
		}

		/// <summary>
		/// Shows the options form.
		/// </summary>
		public void ShowToolsOptions( )
		{
			SoapTraceOptionsEditor Editor = 
				new SoapTraceOptionsEditor( m_FormatterManager.CustomFormatters, m_SoapMessageLoggingManager, m_MainForm );

			Editor.Show( );

			m_MainForm.ActiveView.Manager.RedisplayItemSelected( );
		}

		/// <summary>
		/// Shows the debug messages form.
		/// </summary>
		public void ShowDebugMessages( )
		{
			m_DebugMessageMonitor.ShowDebugMessages( );
		}
		
		/// <summary>
		/// Shows the data packets received.
		/// </summary>
		public void ShowPacketViewer( )
		{	
			m_SoapRequestAndResponses.Clear( );
			m_PacketViewer.Show( m_MainForm );
		}
		
		/// <summary>
		/// Replays the selected soap request.
		/// </summary>
		public void Replay( )
		{
			if( m_MainForm.ActiveView.SelectedItem != null )
			{
				try
				{
					m_MainForm.ActiveView.Manager.Replay( );
				}
				catch( SocketException Ex )
				{
					m_MainForm.ShowError( Ex.Message );
				}
			}
			else
			{
				m_MainForm.ShowError( "No request selected." );
			}
		}
		
		/// <summary>
		/// Opens a new tab.
		/// </summary>
		public void NewTab( )
		{
			MonitorManager Manager = CreateNewMonitorManager( null );
			
			if( ChangeSettings( Manager ) )
			{
				m_MainForm.AddView( Manager.View, GetCaption( Manager.Config ) );
				m_MainForm.Caption = GetCaption( Manager.Config );
				
				m_MainForm.FileCloseTabMenuItemEnabled = true;
									
				SaveSettings( );
			}
		}
		
		/// <summary>
		/// Closes the currently active tab.
		/// </summary>
		public void CloseTab( )
		{
			CloseTab( m_MainForm.ActiveView );
		}
		
		/// <summary>
		/// Closes the tab containing the specified view.
		/// </summary>
		/// <param name="view">A SoapMessagesView that will be closed.</param>
		public void CloseTab( SoapMessagesView view )
		{
			MonitorManager Manager = view.Manager;
			Manager.Stop( );
			
			m_MainForm.RemoveView( view );
			
			if( m_MainForm.ViewCount == 1 )
			{
				m_MainForm.FileCloseTabMenuItemEnabled = false;
			}
			
			m_MonitorManagers.Remove( Manager );
			
			m_MainForm.Caption = m_MainForm.ActiveViewTitle;
			
			// Keep the manager config in case the user wants to undo
			// the close.
			
			SaveManagerConfigForUndo( Manager.Config );
			DisplayUndoCloseMenuItems( );
		}
		
		/// <summary>
		/// A different tab has been selected.
		/// </summary>
		public void TabChanged( )
		{
			m_MainForm.Caption = m_MainForm.ActiveViewTitle;
			
			MonitorManager Manager = m_MainForm.ActiveView.Manager;
			Manager.RedisplayItemSelected( );
		}
		
		/// <summary>
		/// Re-opens a tab.
		/// </summary>
		/// <param name="index">The menu item index clicked by the user.</param>
		public void UndoCloseTab( int index )
		{
			if( index < m_SoapTraceConfiguration.ClosedMonitorManagerConfigurationCollection.Count )
			{
				// Locate matching config.
				MonitorManagerConfiguration Config = m_SoapTraceConfiguration.ClosedMonitorManagerConfigurationCollection[ index ];
				
				// Open up a new tab.
				MonitorManager Manager = CreateNewMonitorManager( Config );
			
				m_MainForm.AddView( Manager.View, GetCaption( Config ) );
				m_MainForm.Caption = GetCaption( Config );
				
				m_MainForm.FileCloseTabMenuItemEnabled = true;
									
				SaveSettings( );

				// Update the undo close menu.
				m_SoapTraceConfiguration.ClosedMonitorManagerConfigurationCollection.Remove( Config );
				DisplayUndoCloseMenuItems( );
			}
		}
		
		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		[ STAThread ]
		static int Main( string[ ] args ) 
		{
			Application.EnableVisualStyles();
			SoapTraceApplication App = new SoapTraceApplication( );
			return SingleInstanceApplication.Run( App, args );
		}

		/// <summary>
		/// Reads the soap trace application's configuration.
		/// </summary>
		private void ReadConfiguration( )
		{	
			Logger.Log( "Reading config..." );
			
			m_SoapTraceConfiguration = SoapTraceConfiguration.Load( );
			
			m_DebugMessageMonitor.MessageLimit = m_SoapTraceConfiguration.DebugMessagesCount;			
			m_DebugMessageMonitor.Level = m_SoapTraceConfiguration.DebugLogLevel;
			m_DebugMessageMonitor.LogBytesAsString = m_SoapTraceConfiguration.DebugLogBytesAsString;
			
			m_MainForm.Configuration = m_SoapTraceConfiguration.MainFormConfiguration;
			m_MainForm.ViewDebugMessages = m_SoapTraceConfiguration.DebugMessages;
			
			Logger.Log( "Read config." );
		}

		/// <summary>
		/// Creates message formatter objects for the currently configured
		/// entries in the config file.  
		/// </summary>
		/// <remarks>We currently support multiple message
		/// formatter objects.  For each one specified in the
		/// config file we create an instance of the formatter object.  The
		/// stored formatter objects will be used to format the soap
		/// messages based on the currently selected formatter.</remarks>
		private void CreateMessageFormatters( )
		{
			m_FormatterManager = new MessageFormatterManager( m_SoapTraceConfiguration.MessageFormatterEntries );
			
			m_FormatterManager.ShowRawSoapMessage = m_SoapTraceConfiguration.MainFormConfiguration.ViewRawSoapMessage;
			m_FormatterManager.ShowSoapEnvelope = m_SoapTraceConfiguration.MainFormConfiguration.ViewSoapEnvelope;
			m_FormatterManager.ShowSoapHeaders = m_SoapTraceConfiguration.MainFormConfiguration.ViewHttpHeaders;
			m_FormatterManager.ShowSoapMessageParameters = m_SoapTraceConfiguration.MainFormConfiguration.ViewSoapMessageParameters;
		
			SetRequestTextReadOnlyState( );
		}

		/// <summary>
		/// Add the message formatter names to the main form's menu.
		/// </summary>
		private void AddMessageFormattersMenuOptions( )
		{
			m_MainForm.AddFormatterMenuItems( m_FormatterManager.GetCustomFormatterNames( ) );
		}

		/// <summary>
		/// Checks the formatter with the specified name and unchecks all 
		/// the other formatters in the View menu.
		/// </summary>
		/// <param name="selectedName">The formatter name to mark as in use.</param>
		private void EnableFormatterMenuItem( string selectedName )
		{
			foreach( string Name in m_FormatterManager.GetCustomFormatterNames( ) )
			{
				if( Name == selectedName )
				{
					m_MainForm.ViewFormatterChecked( selectedName, true );
				}
				else
				{
					m_MainForm.ViewFormatterChecked( selectedName, false );
				}
			}
		}

		/// <summary>
		/// Initialises the soap monitor object.
		/// </summary>
		private void InitSoapMonitors( )
		{
			Logger.Log( "Initialising soap monitors..." );
			
			// Set up default one.
			MonitorManager DefaultManager = new MonitorManager( m_MainForm.ActiveView, m_FormatterManager );
			m_MonitorManagers.Add( DefaultManager );
			DefaultManager.IsConfigured = true;
			m_MainForm.ActiveViewTitle = GetCaption( DefaultManager.Config );
			
			// Set up configured managers.
			
			for( int i = 0; i < m_SoapTraceConfiguration.MonitorManagerConfigurationCollection.Count; ++i )
			{
				MonitorManagerConfiguration Config = 
					m_SoapTraceConfiguration.MonitorManagerConfigurationCollection[ i ];
				
				if( i == 0 )
				{
					DefaultManager.Config = Config; 
					DefaultManager.MatchedResponse += new MatchedResponseEventHandler( MatchedItem );
					m_MainForm.ActiveViewTitle = GetCaption( DefaultManager.Config );
				}
				else
				{
					MonitorManager Manager = CreateNewMonitorManager( Config );
					m_MainForm.AddView( Manager.View, GetCaption( Manager.Config ) );
				}
			}
			
			// Enable close tab menu item.
			
			if( m_MonitorManagers.Count > 1 )
			{
				m_MainForm.FileCloseTabMenuItemEnabled = true;
			}
			
			Logger.Log( "Initialised soap monitors." );
		}

		/// <summary>
		/// Starts the soap message monitor.
		/// </summary>
		private void StartSoapMonitors( )
		{
			Logger.Log( "Starting soap monitors..." );

			foreach( MonitorManager Manager in m_MonitorManagers )
			{
				Manager.Start( );
			}
			
			Logger.Log( "Started soap monitors." );
		}
		
		/// <summary>
		/// Gets the network interfaces on this machine and updates the
		/// sender <see cref="SettingsForm"/> so it can display them.
		/// </summary>
		private void OnGetNetworkInterfaces( object sender, EventArgs e )
		{
			SettingsForm Form = ( SettingsForm )sender;
					
			try
			{
				if( Form.UseRawSockets )
				{
					Form.AddNetworkInterfaceNames( SoapMessageMonitor.GetRawSocketNetworkInterfaceNames( ) );
				}
				else if( Form.UseWinPcap )
				{
					Form.AddNetworkInterfaceNames( SoapMessageMonitor.GetWinPcapNetworkInterfaceNames( ) );
				}
			}
			catch( WinPcapException Ex )
			{
				Logger.LogError( Ex.ToString( ) );
				m_MainForm.ShowError( Ex.Message );				
			}
			catch( DllNotFoundException Ex )
			{
				Logger.LogError( Ex.ToString( ) );
				m_MainForm.ShowError( Ex.Message );
			}

		}
		
		/// <summary>
		/// Saves the current user's settings.
		/// </summary>
		private void SaveSettings( )
		{
			// Save monitor manager config.
			m_SoapTraceConfiguration.MonitorManagerConfigurationCollection.Clear( );
			
			foreach( MonitorManager Manager in m_MonitorManagers )
			{
				if( Manager.IsConfigured )
				{
					m_SoapTraceConfiguration.MonitorManagerConfigurationCollection.Add( Manager.Config );
				}
			}
			
			m_SoapTraceConfiguration.DebugLogLevel = m_DebugMessageMonitor.Level;
			m_SoapTraceConfiguration.DebugMessagesCount = m_DebugMessageMonitor.MessageLimit;
			m_SoapTraceConfiguration.DebugLogBytesAsString = m_DebugMessageMonitor.LogBytesAsString;
			
			m_SoapTraceConfiguration.MainFormConfiguration = m_MainForm.Configuration;
			
			m_SoapTraceConfiguration.Save( );
		}
		
		/// <summary>
		/// Handles unhandled exceptions.
		/// </summary>
		/// <param name="sender">The event source.</param>
		/// <param name="args">The event arguments.</param>
		private void OnUnhandledException( object sender, UnhandledExceptionEventArgs args)
		{
   			Exception Ex = ( Exception )args.ExceptionObject;
   			
   			using( ErrorReportingForm Form = new ErrorReportingForm( ) )
   			{
   				Form.Owner = m_MainForm;
   				Form.ShowDialog( "Unhandled exception.", Ex );
   			}
		}
		
		/// <summary>
		/// Handles unhandled thread exceptions.
		/// </summary>
		/// <param name="sender">The event source.</param>
		/// <param name="args">The event arguments.</param>
		private void OnThreadException( object sender, ThreadExceptionEventArgs args )
		{
			Exception Ex = ( Exception )args.Exception;
   			
   			using( ErrorReportingForm Form = new ErrorReportingForm( ) )
   			{
    			Form.Owner = m_MainForm;
  				Form.ShowDialog( "Unhandled thread exception.", Ex );
   			}
		}	
		
		/// <summary>
		/// Disposes managed and unmanaged objects. 
		/// </summary>
		/// <param name="disposing">If <see langword="true"/> the method has been called directly
		/// or indirectly by a user's code. Managed and unmanaged resources
		/// can be disposed.
		/// If disposing equals <see langword="false"/>, the method has been called by the 
		/// runtime from inside the finalizer and you should not reference 
		/// other objects. Only unmanaged resources can be disposed.
		/// </param>
		private void Dispose( bool disposing )
		{
			if( !m_Disposed )
			{
				if( disposing )
				{
					// Dispose managed resources.
					
					if( m_DebugMessageMonitor != null )
					{
						m_DebugMessageMonitor.Dispose( );
					}
					
					if( m_MainForm != null )
					{
						m_MainForm.Dispose( );
					}
				}
			}

			m_Disposed = true;         
		}		
		
		/// <summary>
		/// Creates the <see cref="PacketViewer"/> object.
		/// </summary>
		private void CreatePacketViewer( )
		{
			m_PacketViewer = new PacketViewer( );
			m_PacketViewer.SoapRequestMessageReceived += new SoapRequestMessageReceivedEventHandler( OnSoapRequestReceived );
		    m_PacketViewer.SoapResponseMessageReceived += new SoapResponseMessageReceivedEventHandler( OnSoapResponseReceived );
						
			// Hook up packet received events.
			
			foreach( MonitorManager Manager in m_MonitorManagers )
			{
				Manager.Monitor.PacketReceived += 
				 	new PacketReceivedEventHandler( m_PacketViewer.AddPacket );
		
				Manager.Monitor.IPPacketReceived += 
					new PacketReceivedEventHandler( m_PacketViewer.AddIPPacket );
			}
		}
		
		/// <summary>
		/// Creates the <see cref="SoapMessageLoggingManager"/>.
		/// </summary>
		private void CreateSoapMessageLoggingManager( )
		{
			m_SoapMessageLoggingManager = new SoapMessageLoggingManager( m_SoapTraceConfiguration.SoapMessageLoggerConfiguration );
		}
			
		/// <summary>
		/// Sets the request text read only state.
		/// </summary>
		private void SetRequestTextReadOnlyState( )
		{
			if( m_FormatterManager.IsCustomFormatterSelected )
			{
				m_MainForm.RequestTextReadOnly = true;
			}
			else if( ( m_FormatterManager.ShowSoapEnvelope == false ) ||
			        m_FormatterManager.ShowSoapMessageParameters )
			{
				m_MainForm.RequestTextReadOnly = true;
			}
			else
			{
				m_MainForm.RequestTextReadOnly = false;
			}
		}
		
		/// <summary>
		/// Logs matched soap request/response pair.
		/// </summary>
		private void MatchedItem( object sender, MatchedResponseEventArgs e )
		{
			// Log message.
			
			MonitorManager Manager = ( MonitorManager )sender;
			
			m_SoapMessageLoggingManager.Log( Manager.Monitor.RemoteServerIPAddress,
				Manager.Monitor.RemoteServerPort,
				e.Item );
		}
		
		/// <summary>
		/// Soap request received from packet viewer.
		/// </summary>
		private void OnSoapRequestReceived( object source, SoapRequestReceivedEventArgs e )
		{
			SoapRequestAndResponse Item = new SoapRequestAndResponse( e.ClientId, e.Request );
			m_SoapRequestAndResponses.Add( Item );

			m_MainForm.ActiveView.AppendItem( Item );
		}
		
		/// <summary>
		/// Soap response received from packet viewer.
		/// </summary>
		private void OnSoapResponseReceived( object source, SoapResponseReceivedEventArgs e )
		{
			SoapRequestAndResponse MatchedItem = 
				m_SoapRequestAndResponses.AddResponse( e.ClientId, e.Response );
				
			if( MatchedItem == null )
			{
				SoapRequestAndResponse Item = new SoapRequestAndResponse( e.ClientId );
				Item.Response = e.Response;

				m_SoapRequestAndResponses.Add( Item );

				m_MainForm.ActiveView.AppendItem( Item );
			}
		}	
		
		/// <summary>
		/// Gets the caption to be displayed in the tab and the 
		/// title bar.
		/// </summary>
		/// <param name="config">A <see cref="MonitorManagerConfiguration"/>
		/// object.</param>
		/// <returns>A caption string.</returns>
		private string GetCaption( MonitorManagerConfiguration config )
		{
			string Caption = String.Empty;
			
			if( config.UseProxyServer )
			{
				Caption = String.Concat( "localhost:", 
					config.ProxyServerListeningPort.ToString( CultureInfo.InvariantCulture ),
					" --> ", 
					config.RemoteServerIPAddress, 
					":", 
					config.RemoteServerPort.ToString( CultureInfo.InvariantCulture ) );
			}
			else
			{
				Caption = String.Concat( "localhost --> ",
				    config.RemoteServerIPAddress, 
					":", 
					config.RemoteServerPort.ToString( CultureInfo.InvariantCulture ) );			                                 
			}
			
			return Caption;
		}
		
		/// <summary>
		/// Creates a new monitor manager.
		/// </summary>
		/// <param name="config">The manager's configuration.</param>
		/// <returns>A new monitor manager.</returns>
		private MonitorManager CreateNewMonitorManager( MonitorManagerConfiguration config )
		{
			SoapMessagesView View = new SoapMessagesView( );
			MonitorManager Manager = new MonitorManager( View, m_FormatterManager );
			View.Manager = Manager;
			Manager.MatchedResponse += new MatchedResponseEventHandler( MatchedItem );

			if( config != null )
			{
				Manager.Config = config;
			}
			
			m_MonitorManagers.Add( Manager );
			
			return Manager;
		}
		
		/// <summary>
		/// Changes the proxy server or packet capture settings for the specified
		/// manager.
		/// </summary>
		/// <returns>
		/// <see langword="true"/> if the user clicked the OK
		/// button on the settings dialog; otherwise <see langword="false"/>.
		/// </returns>
		private bool ChangeSettings( MonitorManager manager )
		{
			// Show the settings form.
			bool Changed = false;	
			SettingsForm Form = new SettingsForm( );
						
			Form.RemoteServerPort = manager.Monitor.RemoteServerPort;
			Form.RemoteServerIPAddress = manager.Monitor.RemoteServerIPAddress;
			Form.ProxyServerListeningPort = manager.Monitor.ProxyServerListeningPort;
			Form.UseProxyServer = manager.Monitor.UseProxyServer;
			Form.UseWinPcap = manager.Monitor.UseWinPcap;
			Form.UseRawSockets = manager.Monitor.UseRawSockets;
							
			// Set network interface names available on this machine.	
			
			try
			{
				if( manager.Monitor.UseWinPcap )
				{
					Form.AddNetworkInterfaceNames( SoapMessageMonitor.GetWinPcapNetworkInterfaceNames( ) );
				}
				else if( manager.Monitor.UseRawSockets )
				{
					Form.AddNetworkInterfaceNames( SoapMessageMonitor.GetRawSocketNetworkInterfaceNames( ) );
				}
			}
			catch( WinPcapException Ex )
			{
				m_MainForm.ShowError( Ex.Message );
			}
			catch( SocketException Ex )
			{
				m_MainForm.ShowError( Ex.Message );					
			}
			catch( DllNotFoundException Ex )
			{
				m_MainForm.ShowError( Ex.Message );
			}
			
			Form.SelectedNetworkInterface = manager.Monitor.NetworkInterfaceName;

			// Hook up GetNetworkInterfaces event.	
		
			Form.GetNetworkInterfaces += new EventHandler( OnGetNetworkInterfaces );
			
			DialogResult Result = Form.ShowDialog( );
			Form.Dispose( );

			try
			{
				if( Result == DialogResult.OK )
				{
					Changed = true;
					
					// Update the current settings.
					
					manager.Stop( );

					manager.Monitor.RemoteServerPort = Form.RemoteServerPort;
					manager.Monitor.RemoteServerIPAddress = Form.RemoteServerIPAddress;
					manager.Monitor.ProxyServerListeningPort = Form.ProxyServerListeningPort;
					manager.Monitor.UseProxyServer = Form.UseProxyServer;
					manager.Monitor.UseWinPcap = Form.UseWinPcap;
					manager.Monitor.UseRawSockets = Form.UseRawSockets;
					manager.Monitor.NetworkInterfaceName = Form.SelectedNetworkInterface;
						
					manager.IsConfigured = true;
					manager.Start( );
				}
			}
			catch( WinPcapException Ex )
			{
				m_MainForm.ShowError( Ex.Message );				
			}
			catch( SocketException Ex )
			{
				m_MainForm.ShowError( Ex.Message );
			}			                           
			catch( DllNotFoundException Ex )
			{
				m_MainForm.ShowError( Ex.Message );
			}
			
			return Changed;
		}
		
		/// <summary>
		/// Stores the config so we can undo the tab close.
		/// </summary>
		void SaveManagerConfigForUndo( MonitorManagerConfiguration config )
		{
			if( m_SoapTraceConfiguration.MaxCloseHistoryItems > 0 )
			{
				while( m_SoapTraceConfiguration.ClosedMonitorManagerConfigurationCollection.Count >= 
				      m_SoapTraceConfiguration.MaxCloseHistoryItems )
				{
					m_SoapTraceConfiguration.ClosedMonitorManagerConfigurationCollection.RemoveAt( m_SoapTraceConfiguration.ClosedMonitorManagerConfigurationCollection.Count - 1 );
				}
				
				m_SoapTraceConfiguration.ClosedMonitorManagerConfigurationCollection.Insert( 0, config );
			}
		}
		
		/// <summary>
		/// Updates the undo close menu items.
		/// </summary>
		void DisplayUndoCloseMenuItems( )
		{
			if( m_SoapTraceConfiguration.ClosedMonitorManagerConfigurationCollection.Count > 0 )
			{
				m_MainForm.UndoCloseMenuItemEnabled = true;		
				
				m_MainForm.ClearUndoCloseMenuItems( );
				
				foreach( MonitorManagerConfiguration Config in m_SoapTraceConfiguration.ClosedMonitorManagerConfigurationCollection )
				{
					m_MainForm.AddUndoCloseMenuItem( GetCaption( Config ) );
				}
			}
			else
			{
				m_MainForm.ClearUndoCloseMenuItems( );
				m_MainForm.UndoCloseMenuItemEnabled = false;
			}
		}
	}
}
